//
//  NBJRootViewController.m
//  nbj
//
//  Created by Francois Proulx on 09-09-20.
//  Copyright 2009 Toujours Saoul. All rights reserved.
//

#import "NBJRootViewController.h"

#import "NBJEvent.h"
#import "NBJEventAnnotation.h"

#import "NBJSuggestionAnnotation.h"
#import "NBJSuggestionPinAnnotationView.h"

@interface NBJRootViewController()

@property (nonatomic, retain) EventsGeoRSSImporter *importer;
@property (nonatomic, readonly) NSOperationQueue *operationQueue;

@property (nonatomic, retain) NSFetchedResultsController *eventResultsController;
@property (nonatomic, retain) NSMutableArray *filteredEventsList;

@property (nonatomic, retain) UIAcceleration *lastAcceleration;

@property (nonatomic, retain) NBJSuggestionAnnotation *barSuggestionAnnotation;
@property (nonatomic, retain) NBJEventAnnotation *selectedBarAnnotation;

// View mode
- (void) switchViewToMode:(NBJRootViewControllerMode)aMode animated:(BOOL)animated;

// Update events list
- (void) updateEventsList:(BOOL)forced;

// Cell configuration
- (void) configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexPath;
- (void) configureSearchResultCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexPath;

@end

@implementation NBJRootViewController

@synthesize contentView;
@synthesize mapView;
@synthesize tableView;
@synthesize modeSelectionControl;
@synthesize toolbar;

@synthesize importer;

@synthesize eventResultsController;
@synthesize filteredEventsList;

@synthesize lastAcceleration;

@synthesize barSuggestionAnnotation;
@synthesize selectedBarAnnotation;

- (void) awakeFromNib
{
	currentMode = NBJRootViewControllerModeUnknown;
}

- (void)dealloc 
{
	self.contentView = nil;
	self.mapView = nil;
	self.tableView = nil;
	self.modeSelectionControl = nil;
	self.toolbar = nil;
	
	self.importer = nil;
	[operationQueue release];
	
	eventResultsController.delegate = nil;
	self.eventResultsController = nil;
	self.filteredEventsList = nil;
	
	self.lastAcceleration = nil;
	
	self.barSuggestionAnnotation = nil;
	self.selectedBarAnnotation = nil;
	
    [super dealloc];
}

- (void)viewDidUnload 
{
	currentMode = NBJRootViewControllerModeUnknown;
	self.contentView = nil;
	self.mapView = nil;
	self.tableView = nil;
	self.modeSelectionControl = nil;
	self.toolbar = nil;
	
	self.importer = nil;
	[operationQueue release];
	
	eventResultsController.delegate = nil;
	self.eventResultsController = nil;
	self.filteredEventsList = nil;
	
	self.lastAcceleration = nil;
	
	self.barSuggestionAnnotation = nil;
	self.selectedBarAnnotation = nil;
	
	[super viewDidUnload];
}

- (void) viewDidLoad 
{
    [super viewDidLoad];
	
	[self switchViewToMode:NBJRootViewControllerModeMap animated:NO];
	
	NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
	[fetchRequest setEntity:[NSEntityDescription entityForName:@"Event" inManagedObjectContext:mainManagedObjectContext]];
	NSSortDescriptor *nameSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
	NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameSortDescriptor, nil];
	[fetchRequest setSortDescriptors:sortDescriptors];
	[sortDescriptors release];
	[nameSortDescriptor release];
	
	NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
																		  managedObjectContext:mainManagedObjectContext 
																			sectionNameKeyPath:@"name" 
																					 cacheName:@"EventsListCache"];
	
	NSError *error = NULL;
	// Perform initial fetch
	if(![frc performFetch:&error]) {
		NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
		NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
		if(detailedErrors != nil && [detailedErrors count] > 0) {
			for(NSError* detailedError in detailedErrors) {
				NSLog(@"  DetailedError: %@", [detailedError userInfo]);
			}
		} else {
			NSLog(@"  %@", [error userInfo]);
		}
	} else {
		// Set up the map data / the table view will be set up through the data source as needed
		CLLocationCoordinate2D parisCenterCoords;
		parisCenterCoords.latitude = 48.858842;
		parisCenterCoords.longitude = 2.353521;
		mapView.region = MKCoordinateRegionMakeWithDistance(parisCenterCoords, 5000, 5000);
		
		// Attach the FRC to this view controller so it will call us whenever stuff gets updated
		frc.delegate = self;
		self.eventResultsController = frc;
		
		// A secondary will contained filtered search results
		NSMutableArray *newFilteredEventsList = [[NSMutableArray alloc] initWithCapacity:[[eventResultsController fetchedObjects] count]];
		self.filteredEventsList = newFilteredEventsList;
		[newFilteredEventsList release];
	}
	
	[frc release];
	[fetchRequest release];
}

- (void) viewDidAppear:(BOOL)animated
{
	[super viewDidAppear:animated];
	
	// Shake support
	shakeCount = 0;
	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 15)];
	[UIAccelerometer sharedAccelerometer].delegate = self;
	
	// Download new events list, as needed, then reset the flag
	[self updateEventsList:[[NSUserDefaults standardUserDefaults] boolForKey:NBJAPNSForcedUpdate]];
	[[NSUserDefaults standardUserDefaults] setBool:NO forKey:NBJAPNSForcedUpdate];
}

- (void) viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
	
	[UIAccelerometer sharedAccelerometer].delegate = nil;
}

#pragma mark -
#pragma mark IBActions

- (IBAction) geolocate
{
	if(mapView.userLocation.location) {
#if TARGET_IPHONE_SIMULATOR			
		CLLocationCoordinate2D parisCenterCoords;
		parisCenterCoords.latitude = 48.858842;
		parisCenterCoords.longitude = 2.353521;
		
		// Zoom to some debug coords
		[mapView setRegion:MKCoordinateRegionMakeWithDistance(parisCenterCoords, 500, 500) animated:YES];
#else
		// Zoom to user location
		[mapView setRegion:MKCoordinateRegionMakeWithDistance(mapView.userLocation.coordinate, 500, 500) animated:YES];
#endif
	}
}

- (IBAction) rootViewModeChanged:(UISegmentedControl *)aModeSelectionControl
{
	[self switchViewToMode:((NBJRootViewControllerMode)modeSelectionControl.selectedSegmentIndex) 
				  animated:YES];
}

- (IBAction) suggestNewBar
{
	if([MFMailComposeViewController canSendMail]) {
		if(mapView.userLocation.location) {
			// Only allow one suggestion at at time
			if(!barSuggestionAnnotation) {
#if TARGET_IPHONE_SIMULATOR			
				CLLocationCoordinate2D parisCenterCoords;
				parisCenterCoords.latitude = 48.858842;
				parisCenterCoords.longitude = 2.353521;
				NBJSuggestionAnnotation *newBarSuggestionAnnotation = [[NBJSuggestionAnnotation alloc] initWithCoordinate:parisCenterCoords];
#else
				// Shift some distance up the actual location to avoid touching the user location pin
				CLLocationCoordinate2D shiftedCoords = mapView.userLocation.coordinate;
				shiftedCoords.latitude += 0.0002; 
				NBJSuggestionAnnotation *newBarSuggestionAnnotation = [[NBJSuggestionAnnotation alloc] initWithCoordinate:shiftedCoords];
#endif
				
				// Add annotation
				self.barSuggestionAnnotation = newBarSuggestionAnnotation;
				[mapView addAnnotation:barSuggestionAnnotation];
				[newBarSuggestionAnnotation release];
			}
			
			// Zoom to, select annotation
			[mapView setRegion:MKCoordinateRegionMakeWithDistance(barSuggestionAnnotation.coordinate, 200, 200) animated:YES];
			[mapView selectAnnotation:barSuggestionAnnotation animated:YES];
		} else {
			UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"NBJ" 
															message:@"Avant d'ajouter un bar, votre position doit déjà apparaître sur la carte." 
														   delegate:nil 
												  cancelButtonTitle:@"OK" 
												  otherButtonTitles:nil];
			[alert show];
			[alert release];
		}		
	} else {
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"NBJ" 
														message:@"Vous devez configurer un compte e-mail avant de pouvoir suggérer un bar." 
													   delegate:nil 
											  cancelButtonTitle:@"OK" 
											  otherButtonTitles:nil];
		[alert show];
		[alert release];
	}
}

- (void) switchViewToMode:(NBJRootViewControllerMode)aMode animated:(BOOL)animated
{
	if(currentMode != aMode) {
		currentMode = aMode;
		modeSelectionControl.selectedSegmentIndex = aMode;
		
		if(animated) {
			[UIView beginAnimations:@"CurlAnimation" context:NULL];
			[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
			[UIView setAnimationDuration:1.0];
			
			switch (currentMode) {
				case NBJRootViewControllerModeMap:
					[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:contentView cache:YES];
					break;
				case NBJRootViewControllerModeList:
					[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:contentView cache:YES];
					break;
			}
		}
		
		switch (currentMode) {
			case NBJRootViewControllerModeMap:
				[tableView removeFromSuperview];
				mapView.frame = contentView.bounds;
				[contentView addSubview:mapView];
				break;
			case NBJRootViewControllerModeList:
				[mapView removeFromSuperview];
				tableView.frame = contentView.bounds;
				[contentView addSubview:tableView];
				break;
		}
		
		if(animated) {
			[UIView commitAnimations];
		}
		
	}
}

#pragma mark -
#pragma mark Shake to shuffle support

- (void) shakeToShuffle
{
	// Choose an annotation at random
	NSArray *annotationsList = [mapView annotations];
	NSUInteger annotationsCount = [annotationsList count];
	if(annotationsCount > 0) {
		// Hide search interface
		[self.searchDisplayController setActive:NO animated:YES];
		
		// Make sure that we are in map mode and select some annotation
		[self switchViewToMode:NBJRootViewControllerModeMap animated:YES];
		
		// Shuffle (ignoring user location marker)
		NBJEventAnnotation *randomAnnotation = nil;
		NSUInteger shuffleCount = 0;
		while(shuffleCount <= 5 && (randomAnnotation = [annotationsList objectAtIndex:(arc4random() % annotationsCount)])) {
			if(![randomAnnotation isKindOfClass:[MKUserLocation class]]) {
				// Zoom and select random annotation on the map
				[mapView setRegion:MKCoordinateRegionMakeWithDistance(randomAnnotation.coordinate, 1000, 1000) animated:YES];
				[mapView selectAnnotation:randomAnnotation animated:YES];
				
				// Vibrate the phone
				AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
				break;
			}
			
			shuffleCount++;
			randomAnnotation = nil;
		}
	}
}

- (BOOL) accelerationDeltaIsShakeLast:(UIAcceleration *)last current:(UIAcceleration *)current threshold:(double)threshold {
    double
    deltaX = fabs(last.x - current.x),
    deltaY = fabs(last.y - current.y),
    deltaZ = fabs(last.z - current.z);
	
    return
    (deltaX > threshold && deltaY > threshold) ||
    (deltaX > threshold && deltaZ > threshold) ||
    (deltaY > threshold && deltaZ > threshold);
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    if (self.lastAcceleration) {
        if ([self accelerationDeltaIsShakeLast:self.lastAcceleration current:acceleration threshold:0.7] && shakeCount >= 9) {
			shakeCount = 0;
			[self shakeToShuffle];
        } else if ([self accelerationDeltaIsShakeLast:self.lastAcceleration current:acceleration threshold:0.7]) {
			shakeCount = shakeCount + 5;
        }else if (![self accelerationDeltaIsShakeLast:self.lastAcceleration current:acceleration threshold:0.2]) {
			if (shakeCount > 0) {
				shakeCount--;
			}
        }
    }
    self.lastAcceleration = acceleration;
}

#pragma mark -
#pragma mark Events list processing

- (NSOperationQueue *) operationQueue 
{
    if (operationQueue == nil) {
        operationQueue = [[NSOperationQueue alloc] init];
    }
    return operationQueue;
}

- (void) updateEventsList:(BOOL)forced
{
	BOOL importStarted = NO;
	
	// Only allow one events download at a time
	if(!self.importer) {
		NSDate *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:NBJEventsListLastUpdateUserDefaultsKey];
		if (forced || lastUpdate == nil || -[lastUpdate timeIntervalSinceNow] > NBJEventsListRefreshTimeInterval) {
			if(self.internetConnectionAvailable) {
				// Remove markers, they'll be added gradually by the callback
				[mapView removeAnnotations:[mapView annotations]];
				
				// create an importer object to retrieve, parse, and import into the CoreData store 
				self.importer = [[[EventsGeoRSSImporter alloc] init] autorelease];
				importer.delegate = self;
				
				// pass the coordinator so the importer can create its own managed object context
				importer.persistentStoreCoordinator = [self.mainManagedObjectContext persistentStoreCoordinator];
				[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
				
				// add the importer to an operation queue for background processing (works on a separate thread)
				[self.operationQueue addOperation:importer];
				importStarted = YES;
			} else {
				UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"NBJ" 
																message:@"Vous devez être connecté pour mettre à jour la liste des bars." 
															   delegate:nil 
													  cancelButtonTitle:@"OK" 
													  otherButtonTitles:nil];
				[alert show];
				[alert release];
			}
		}
	}
	
	if(!importStarted) {
		// In case we could not start the download, we need to display local cacche, if any, right away.
		NSArray *annotations = [[eventResultsController fetchedObjects] valueForKeyPath:@"annotation"];
		[mapView addAnnotations:annotations];
	}
}

#pragma mark <EventsGeoRSSImporterDelegate> Implementation

- (void) importerDidSave:(NSNotification *)saveNotification 
{
	if ([NSThread isMainThread]) {
		[self.mainManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
	} else {
		[self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
	}
}

- (void) importerDidFinishParsingData:(EventsGeoRSSImporter *)importer 
{
	if ([NSThread isMainThread]) {
		[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:NBJEventsListLastUpdateUserDefaultsKey];
		[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
		self.importer = nil;
	} else {
		[self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
	}
}

- (void) importer:(EventsGeoRSSImporter *)importer didFailWithError:(NSError *)error 
{
	if ([NSThread isMainThread]) {
		[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
		self.importer = nil;
	} else {
		[self performSelectorOnMainThread:_cmd withObject:error waitUntilDone:NO];
	}
}

#pragma mark -
#pragma mark NSFetchedResultsControllerDelegate

- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller 
{
    [tableView beginUpdates];
}

- (void) controller:(NSFetchedResultsController *)controller 
   didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
			atIndex:(NSUInteger)sectionIndex 
	  forChangeType:(NSFetchedResultsChangeType)type 
{	
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
						  withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
						  withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void) controller:(NSFetchedResultsController *)controller 
	didChangeObject:(id)anObject
		atIndexPath:(NSIndexPath *)indexPath 
	  forChangeType:(NSFetchedResultsChangeType)type
	   newIndexPath:(NSIndexPath *)newIndexPath 
{
	// Insert new rows and annotations as we received data
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
							 withRowAnimation:UITableViewRowAnimationFade];
			[mapView addAnnotation:[anObject annotation]];
            break;
    }
}

- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller 
{
    [tableView endUpdates];
}

#pragma mark -
#pragma mark UITableViewDataSource

- (NSInteger) numberOfSectionsInTableView:(UITableView *)aTableView 
{
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
        return 1;
    } else {
		return [[eventResultsController sections] count];
	}
}

- (NSInteger) tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section 
{	
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
        return [filteredEventsList count];
    } else {
		NSArray *sections = [eventResultsController sections];
		NSUInteger count = 0;
		if ([sections count]) {
			id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
			count = [sectionInfo numberOfObjects];
		}
		return count;
	}
}

- (void) configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexPath
{
	NBJEvent *event = (NBJEvent *) [eventResultsController objectAtIndexPath:indexPath];
	aCell.accessoryType = UITableViewCellAccessoryNone;
	aCell.textLabel.text = [event eventDescription];
	aCell.detailTextLabel.text = event.address;
}

- (void) configureSearchResultCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexPath
{
	NBJEvent *event = (NBJEvent *) [filteredEventsList objectAtIndex:indexPath.row];
	aCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
	aCell.textLabel.text = [event eventDescription];
	aCell.detailTextLabel.text = event.address;
}

- (UITableViewCell *) tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{	
	static NSString *reuseIdentifier = @"eventCell";
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:reuseIdentifier];
	if (!cell) {
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
	}
	
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
		[self configureSearchResultCell:cell atIndexPath:indexPath];
    } else {
		[self configureCell:cell atIndexPath:indexPath];
	}
	
    return cell;
}

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	[aTableView deselectRowAtIndexPath:indexPath animated:YES];
	
	NBJEvent *event = nil;
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
        event = (NBJEvent *) [filteredEventsList objectAtIndex:indexPath.row];
    } else {
        event = (NBJEvent *) [eventResultsController objectAtIndexPath:indexPath];
    }
	
	// Scan through annotations to find the one that represents the event
	NBJEventAnnotation *eventAnnotation = nil;
	for(eventAnnotation in [mapView annotations]) {
		if(![eventAnnotation isKindOfClass:[MKUserLocation class]]) {
			if([[eventAnnotation.event objectID] isEqual:[event objectID]]) {
				// Short circuit, we got the annotation we wanted
				break;
			}
		}
	}
	
	if(eventAnnotation) {
		// Hide search interface
		[self.searchDisplayController setActive:NO animated:YES];
		
		// Make sure that we are in map mode, so we can display where the search result is located
		[self switchViewToMode:NBJRootViewControllerModeMap animated:YES];
		[mapView setRegion:MKCoordinateRegionMakeWithDistance(eventAnnotation.coordinate, 1000, 1000) animated:YES];
		[mapView selectAnnotation:eventAnnotation animated:YES];
	}
}

- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)aTableView 
{
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
		return nil;
	} else {
		return [eventResultsController sectionIndexTitles];
	}

}

- (NSInteger) tableView:(UITableView *)aTableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index 
{
	if (aTableView == self.searchDisplayController.searchResultsTableView) {
		return 0;
	} else {
		return [eventResultsController sectionForSectionIndexTitle:title atIndex:index];
	}
}

#pragma mark -
#pragma mark Mapview delegate

- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
	if([annotation isKindOfClass:[MKUserLocation class]]) {
		return nil;
	}
	
	MKAnnotationView *annotationView = nil;
	if([annotation isKindOfClass:[NBJEventAnnotation class]]) {
		// Events pins
		static NSString *reuseIdentifier = @"eventPinAnnotationView";
		annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
		if(!annotationView) {
			annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier] autorelease];
			annotationView.canShowCallout = YES;
			annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
		}
		
		NBJEventAnnotation *eventAnnotation = (NBJEventAnnotation *) annotation;
		annotationView.annotation = annotation;
		
		// Display event as current as long as it's within +/- 3 days of the event date
		if(eventAnnotation.event.date && fabs([eventAnnotation.event.date timeIntervalSinceNow]) <= (3600 * 24 * 3)) {
			annotationView.image = [UIImage imageNamed:@"orange-pin.png"];
			annotationView.centerOffset = CGPointMake(11, -19);
			annotationView.calloutOffset = CGPointMake(-10, -2);
		} else {
			annotationView.image = [UIImage imageNamed:@"blue-pin.png"];
			annotationView.centerOffset = CGPointMake(11, -19);
			annotationView.calloutOffset = CGPointMake(-10, -2);
		}
	} else if([annotation isKindOfClass:[NBJSuggestionAnnotation class]]) {
		
		// Draggable pins (suggestions)
		static NSString *reuseIdentifier = @"NBJSuggestionPinAnnotationView";
		annotationView = (NBJSuggestionPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
		if(!annotationView) {
			annotationView = [[[NBJSuggestionPinAnnotationView alloc] initWithAnnotation:annotation] autorelease];
		}
		
		// The pin needs to know about the coordinate system of the mapview to map the raw point back to coordinates
		((NBJSuggestionPinAnnotationView *) annotationView).map = mapView;
	}
	
	return annotationView;
}

#define NBJAlertViewSelectedBarDetailsTag (1337)
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
	if([view.annotation isKindOfClass:[NBJEventAnnotation class]]) {
		NBJEventAnnotation *annotation = (NBJEventAnnotation *) view.annotation;
		self.selectedBarAnnotation = annotation;
		
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:annotation.event.name 
														message:annotation.event.address
													   delegate:self 
											  cancelButtonTitle:@"Fermer" 
											  otherButtonTitles:@"Itinéraire", nil];
		alert.tag = NBJAlertViewSelectedBarDetailsTag;
		[alert show];
		[alert release];
	} else if([view.annotation isKindOfClass:[NBJSuggestionAnnotation class]]) {
		NBJSuggestionAnnotation *annotation = (NBJSuggestionAnnotation *) view.annotation;
		NSString *externalMapsUrl = [annotation externalMapUrlString];
		NSString *messageBody = [NSString stringWithFormat:@"Voici une suggestion de bar:\r\n<br>Nom du bar: \r\n<br>Adresse: \r\n<br>Description: \r\n<br><br>Lien vers la carte:\r\n<br><a href=\"%@\">%@</a>", externalMapsUrl, externalMapsUrl];

		MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
		[vc setToRecipients:[NSArray arrayWithObject:@"nbj.suggestions@gmail.com"]];
		[vc setSubject:@"NBJ: Suggestion de bar"];
		[vc setMessageBody:messageBody isHTML:YES];
		vc.mailComposeDelegate = self;
		[self presentModalViewController:vc animated:YES];
		[vc release];
	}
}

#pragma mark -
#pragma mark MFMailComposeViewControllerDelegate

- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
	[mapView removeAnnotation:self.barSuggestionAnnotation];
	self.barSuggestionAnnotation = nil;
	[self dismissModalViewControllerAnimated:YES];
	
	if(result == MFMailComposeResultSent) {
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"NBJ"
														message:@"Merci pour cette suggestion."
													   delegate:nil
											  cancelButtonTitle:@"OK"
											  otherButtonTitles:nil];
		[alert show];
		[alert release];
	}
}

#pragma mark -
#pragma mark UIAlertViewDelegate

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
	switch (alertView.tag) {
		case NBJAlertViewSelectedBarDetailsTag:
			if(buttonIndex != alertView.cancelButtonIndex) {
				NSURL *outgoingMapUrl = nil;
				// Build an external map URL, taking in account whether or not the user location is known at this time
				if(mapView.userLocation.location) {
					outgoingMapUrl = [NSURL URLWithString:[selectedBarAnnotation externalRouteUrlStringStartingFrom:mapView.userLocation.coordinate]];
				} else {
					outgoingMapUrl = [NSURL URLWithString:[selectedBarAnnotation externalMapUrlString]];
				}
				
				[[UIApplication sharedApplication] openURL:outgoingMapUrl];
			}
			self.selectedBarAnnotation = nil;
			break;
	}
}

#pragma mark -
#pragma mark Content Filtering

// Update filtered list to match search terms
- (void) filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
	[filteredEventsList removeAllObjects];

	NSInteger numericValue = [searchText integerValue];
	NSNumber *numberSearch = nil;
	if(numericValue != 0) {
		numberSearch = [NSNumber numberWithInteger:numericValue];
	}
	
	// Scan through the events list and gather matching objects
	for (NBJEvent *event in [eventResultsController fetchedObjects]) {
		// Search by numberrc
		if(numberSearch) {
			if([numberSearch isEqual:event.eventId]) {
				[filteredEventsList addObject:event];
			}
		} else {
			// Search by name
			NSRange range = [event.name rangeOfString:searchText 
											  options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
			if (range.location != NSNotFound) {
				[filteredEventsList addObject:event];
			} else {
				// Search by address
				range = [event.address rangeOfString:searchText 
										  options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
				if (range.location != NSNotFound) {
					[filteredEventsList addObject:event];
				}
			}
		}
	}
}

#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
	NSUInteger selectedScopeIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];
	NSString *scope = [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:selectedScopeIndex];
    [self filterContentForSearchText:searchString scope:scope];
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
	NSUInteger selectedScopeIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];
	NSString *scope = [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:selectedScopeIndex];
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:scope];
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


@end
